package com.arpa.ntocc.basic.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import com.arpa.core.utils.text.HashUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.basic.api.cache.WarehouseCache;
import com.arpa.ntocc.basic.api.service.UserService;
import com.arpa.ntocc.common.common.Page;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.cache.PartyCacheDO;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.common.util.ValidateUtil;
import com.arpa.ntocc.common.common.validator.Save;
import com.arpa.ntocc.common.common.validator.Update;
import com.arpa.ntocc.common.domain.dto.PartyAuthorizeDto;
import com.arpa.ntocc.common.domain.dto.UserDto;
import com.arpa.ntocc.common.domain.entity.Party;
import com.arpa.ntocc.common.domain.entity.PartyGroup;
import com.arpa.ntocc.common.domain.entity.PartyResource;
import com.arpa.ntocc.common.domain.entity.UserLogin;
import com.arpa.ntocc.common.domain.enums.PartyStatusEnum;
import com.arpa.ntocc.common.domain.enums.PartyTypeEnum;
import com.arpa.ntocc.common.domain.vo.ResourceVO;
import com.arpa.ntocc.common.domain.vo.UserVo;
import com.arpa.ntocc.common.service.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.codec.Hex;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.rmi.ServerException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author liuyj
 * @since 2019-11-25
 */
@Log4j2
//@Validated
@Service
public class UserServiceImpl implements UserService {


    private static final String DEFAULT_PD = "abcd1234";
    private final static String INVALID_PASSWORD_FORMAT_ALPHANUMERIC_COMBINATION_MORE_THAN_EIGHT_DIGITS = "密码格式不合法，数字字母组合 8位及以上";

    @Resource
    private PartyCache partyCache;
    @Resource
    private ShipmentCache shipmentCache;
    @Resource
    private WarehouseCache warehouseCache;
    private final IPartyGroupService partyGroupService;
    private final IPartyService partyService;
    private final IUserLoginService userLoginService;
    private final IPartyResourceService partyResourceService;
    private final IResourceService resourceService;

    public UserServiceImpl(IPartyGroupService partyGroupService,
                           IPartyService partyService,
                           IUserLoginService userLoginService,
                           IPartyResourceService partyResourceService,
                           IResourceService resourceService
    ) {
        this.partyGroupService = partyGroupService;
        this.partyService = partyService;
        this.userLoginService = userLoginService;
        this.partyResourceService = partyResourceService;
        this.resourceService = resourceService;
    }






    /**
     * 组织授权
     * TODO 需要处理缓存
     *
     * @param dto
     * @author liuxr
     * @date 2021/11/29 16:21
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Validated()
    public void authorize(@Valid PartyAuthorizeDto dto) {
        List<String> resourceCodeList = dto.getResourceCodeList();
        partyResourceService.removeByPartyCode(dto.getPartyCode(), dto.getGroupCode());
        List<PartyResource> partyResourceList = resourceCodeList.stream().map(r -> {
            PartyResource resource = new PartyResource();
            resource.setCode(IdUtil.fastSimpleUUID());
            resource.setResourceCode(r);
            resource.setPartyCode(dto.getPartyCode());
            resource.setGroupCode(dto.getGroupCode());
            return resource;
        }).collect(Collectors.toList());
        //重新授权组织资源信息
        partyResourceService.saveBatch(partyResourceList);
    }


    /**
     * 查询用户信息，包含角色
     *
     * @param code
     * @return
     */
    @Override
    public UserVo getUserDetails(String groupCode, String code) {
        Party party = partyService.getOne(Wrappers.lambdaQuery(Party.class)
                .eq(Party::getCode, code).eq(Party::getBranchCode, groupCode));
        if (null == party) {
            log.error("获取账号失败，找不到账号信息。组织:{}，账号：{}", groupCode, code);
            throw new ServiceException("找不到账号信息");
        }
        UserVo userVo = new UserVo();
        userVo.setPhone(party.getCode());
        userVo.setName(party.getName());
        userVo.setCreatedName(party.getCreatedName());
        userVo.setModifiedName(party.getModifiedName());
        userVo.setGmtCreated(party.getGmtCreated());
        userVo.setGmtModified(party.getGmtModified());
        userVo.setId(party.getId());
        userVo.setGroupCode(party.getBranchCode());
        userVo.setWarehouseName(party.getWarehouseName());
        userVo.setShipmentName(party.getShipmentName());
        String authorizationShipment = party.getAuthorizationShipment();
        if (StrUtil.isNotBlank(authorizationShipment)) {
            List<String> authorizationShipmentCode = StrUtil.split(authorizationShipment, ',');
            if (IterUtil.isNotEmpty(authorizationShipmentCode)) {
                authorizationShipmentCode = authorizationShipmentCode.stream()
                        .map(s -> StrUtil.unWrap(s, "[", "]")).collect(Collectors.toList());
                userVo.setAuthorizationShipmentCode(authorizationShipmentCode.toArray(new String[0]));
            }
        }
        String authorizationWarehouse = party.getAuthorizationWarehouse();
        if (StrUtil.isNotBlank(authorizationWarehouse)) {
            List<String> authorizationWarehouseCode = StrUtil.split(authorizationWarehouse, ',');
            if (IterUtil.isNotEmpty(authorizationWarehouseCode)) {
                authorizationWarehouseCode = authorizationWarehouseCode.stream()
                        .map(s -> StrUtil.unWrap(s, "[", "]")).collect(Collectors.toList());
                userVo.setAuthorizationWarehouseCode(authorizationWarehouseCode.toArray(new String[0]));
            }
        }
        return userVo;
    }
    @Override
    public List<ResourceVO> resourcdTreeData() {
        String branchCode = UserUtil.getBranchCode();
        String partyCode = UserUtil.getCode();
        PartyTypeEnum partyTypeEnum = UserUtil.getPartyType();
        List<PartyResource> partyResourceList ;

        if(partyTypeEnum.equals(PartyTypeEnum.GROUP_ADMIN)){
            partyResourceList = partyResourceService.list(Wrappers.lambdaQuery(PartyResource.class)
                    .select(PartyResource::getResourceCode)
                    .eq(PartyResource::getPartyCode, branchCode));
        }else{
            partyResourceList = partyResourceService.list(Wrappers.lambdaQuery(PartyResource.class)
                    .select(PartyResource::getResourceCode)
                    .eq(PartyResource::getPartyCode, partyCode)
                    .eq(PartyResource::getGroupCode, branchCode));
        }

        Set<String> resourceCodeSet = partyResourceList.stream().map(PartyResource::getResourceCode).collect(Collectors.toSet());
        List<com.arpa.ntocc.common.domain.entity.Resource> resourceList;
        List<ResourceVO> resourceVOList = null;
        if (IterUtil.isNotEmpty(resourceCodeSet)) {
            resourceList = resourceService.list(Wrappers.lambdaQuery(com.arpa.ntocc.common.domain.entity.Resource.class)
                    .in(com.arpa.ntocc.common.domain.entity.Resource::getCode, resourceCodeSet)
            );
            if (IterUtil.isNotEmpty(resourceList)) {
                List<ResourceVO> allResourceVOList = resourceList.stream().map(resource -> {
                    ResourceVO resourceVO = new ResourceVO();
                    BeanUtil.copyProperties(resource, resourceVO);
                    return resourceVO;
                }).collect(Collectors.toList());
                resourceVOList = treeResource(allResourceVOList, 0, 100);
            }
        }
        return resourceVOList;
    }

    /**
     * 组装resource为树形结构
     *
     * @param resourceList
     * @param levelStart   从哪级开始
     * @param maxLevel     最大总共获取多少级
     */
    private List<ResourceVO> treeResource(List<ResourceVO> resourceList, int levelStart, int maxLevel) {
        List<ResourceVO> topResourceList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(resourceList)) {
            topResourceList = resourceList.stream().filter(resourceVO -> resourceVO.getLevel() == levelStart).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(topResourceList)) {
            topResourceList.forEach(resource -> {
                resource.setChild(getChild(resource.getCode(), resourceList, maxLevel));
            });
        }
        return topResourceList;
    }

    /**
     * 获取子列表(递归)
     *
     * @param parentCode   父级code
     * @param resourceList 总数据
     * @param maxLevel     最大总共获取多少级
     * @return
     */
    private List<ResourceVO> getChild(String parentCode, List<ResourceVO> resourceList, int maxLevel) {
        List<ResourceVO> child = resourceList.stream().filter(resource -> parentCode.equals(resource.getParentCode())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(child)) {
            child.forEach(resource -> {
                if (resource.getLevel() < maxLevel) {//最大只展示maxLevel级
                    resource.setChild(getChild(resource.getCode(), resourceList, maxLevel));
                }
            });
        }
        return child;
    }

    @Override
    public List<Map<String, String>> getGroupWarehouse() {
        return partyGroupService.getGroupWarehouse(UserUtil.getBranchCode());
    }

    /**
     * 获取用户已授权资源
     *
     * @param partyCode 账号
     * @return java.util.List<java.lang.String>
     * @author liuxr
     * @date 2021/12/4 9:36
     */
    @Override
    public List<String> getUserAuthorizeResourcd(String partyCode) {




        List<PartyResource> resourceCodeList = partyResourceService.list(Wrappers.lambdaQuery(PartyResource.class)
                .select(PartyResource::getResourceCode).eq(PartyResource::getPartyCode, partyCode));
        if (IterUtil.isNotEmpty(resourceCodeList)) {
            List<String> allResourceCodeList = resourceCodeList.stream().map(PartyResource::getResourceCode).collect(Collectors.toList());
            List<com.arpa.ntocc.common.domain.entity.Resource> allResourceList = resourceService.list(Wrappers.lambdaQuery(com.arpa.ntocc.common.domain.entity.Resource.class)
                    .in(com.arpa.ntocc.common.domain.entity.Resource::getCode, allResourceCodeList));
            //存储所有父节点code到list
            List<String> parentCodeList = allResourceList.stream()
                    .filter(resource -> StringUtils.isNotEmpty(resource.getParentCode()))
                    .map(com.arpa.ntocc.common.domain.entity.Resource::getParentCode).collect(Collectors.toList());
            return resourceCodeList.stream()
                    .filter(roleResource -> !parentCodeList.contains(roleResource.getResourceCode()))
                    .map(PartyResource::getResourceCode).collect(Collectors.toList());
        }
        return null;
    }
}
